﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Vitruvian.Serialization;
using Vitruvian.Serialization.Formatters;
using Vitruvian.Distribution;
using Vitruvian.Distribution.SyncPatterns;
using Vitruvian.Windows.Serialization.Formatters;
using Vitruvian.Logging;
using Vitruvian.Testing;

namespace SpotItComponents
{
    public delegate void GameEventHandler(GameMonitor monitor);
    public delegate void GamePlayerEventHandler(GameMonitor monitor, int playerIndex);

    [DistributionInfo]
    [OptimisticSerialization]
    public class GameMonitor : Component
    {
        #region Private Data Members
        private GameInfo myGame;
        private int playerCount;
        private int myPlayerIndex;
        private PlayingCard centerCard;
        private List<string> playerNames;
        private List<CardStack> playerVisibleCards;
        #endregion

        #region Events
        public event GameEventHandler GameInitialized;
        public event GameEventHandler PlayerJoined;
        public event GameEventHandler GameStarted;
        public event GameEventHandler GameWon;
        public event GameEventHandler GameAborted;
        public event GameEventHandler GamePaused;
        public event GameEventHandler GameResumed;
        public event GameEventHandler CenterCardChanged;
        public event GameEventHandler MyCardsChanged;
        public event GamePlayerEventHandler OtherPlayerCardsChanged;
        #endregion

        public GameMonitor() { }

        [SyncPattern("RPC")]
        public virtual void Initialize( GameInfo gameInfo,
                                        int currentPlayerIndex,
                                        List<string> playerNames)
        {
            this.myGame = gameInfo;
            this.playerCount = playerNames.Count;
            this.myPlayerIndex = currentPlayerIndex;
            this.playerNames = playerNames;

            if (GameInitialized!=null)
                GameInitialized(this);
        }

        [SyncPattern("RPC")]
        public virtual void AddPlayer(string playerName)
        {
            playerCount++;
            this.playerNames.Add(playerName);

            if (PlayerJoined != null)
                PlayerJoined(this);
        }

        public virtual void Start(
                                PlayingCard centerCard,
                                List<CardStack> playerVisibleCards)
        {
            this.centerCard = centerCard;
            this.playerVisibleCards = playerVisibleCards;

            if (GameStarted != null)
                GameStarted(this);
        }

        [SyncPattern("RPC")]
        public virtual void ChangeGameStatus(GameStateType newState)
        {
            GameStateType oldState = this.myGame.State;

            this.myGame.State = newState;
            if (GameWon != null && this.myGame.State == GameStateType.Won)
                GameWon(this);
            else if (GameAborted != null && this.myGame.State == GameStateType.Aborted)
                GameAborted(this);
            else if (GamePaused != null && this.myGame.State == GameStateType.Paused)
                GameAborted(this);
            else if (GameResumed != null && this.myGame.State == GameStateType.InProgress && oldState == GameStateType.Paused)
                GameResumed(this);
        }

        [SyncPattern("RPC")]
        public virtual void ChangeCenterCard(PlayingCard newCenterCard)
        {
            this.centerCard = newCenterCard;
            if (CenterCardChanged != null)
                CenterCardChanged(this);
        }

        [SyncPattern("RPC")]
        public virtual void ChangePlayerVisibleCards(int playerIndex, CardStack playerCards)
        {
            this.playerVisibleCards[playerIndex] = playerCards;
            if (playerIndex == myPlayerIndex)
            {
                if (MyCardsChanged != null)
                    MyCardsChanged(this);
            }
            else
            {
                if (OtherPlayerCardsChanged != null)
                    OtherPlayerCardsChanged(this, playerIndex);
            }
        }

    }
}
